import Utils from "../../Utils";
import DestructibleFacility from "../facility/DestructibleFacility";
import Facility from "../facility/Facility";
import MainHome from "../facility/priveteFacility/MainHome";
import Mine from "../facility/pulbicFacility/Mine";
import Flyer from "../flyer/Flyer";
import { Killer } from "../funcObj/interface/HealthPoint";
import { FacilityType } from "../info/GameEnum";
import { Global } from "../info/Global";
import { Location, MapLength } from "../info/Predefine";
import GameManager from "../manager/GameManager";
import Player from "../player/Player";
import AiFindHome from "./AiPlayer/AiFindHome";
import AiGmaeAction from "./AiPlayer/AiGameAction";

const { ccclass, property } = cc._decorator;

@ccclass
export default class AiPlayer extends Player {
    aiGameAction: AiGmaeAction;

    public get facilityHpColor(): cc.SpriteFrame {
        return GameManager.instance.enemyHpColors[0];
    }

    public get flyerhpColor(): cc.SpriteFrame {
        return GameManager.instance.enemyHpColors[1];
    }

    public get flyerParentNode(): cc.Node {
        return GameManager.instance.underFlyerParent;
    }

    /**
     * 记录所有视野地图块
     */
    viewArr: Uint8Array = null;

    /**
     * 攻击过我的设施的设施(设施毁灭后及时清除)
     * <攻击过我的设施，造成的伤害>
     */
    facilityHurtMyFacility: Map<DestructibleFacility, number>;

    /**
     * 攻击过我飞行物的设施（近防炮）
     * <攻击过我飞行物的设施，造成的伤害>
     */
    facilityHurtMyFlyer: Map<DestructibleFacility, number>;

    /**
     * 我的设施受到的伤害
     * <我的设施，受到的伤害>
     */
    facilityMyHurt: Map<DestructibleFacility, number>;

    _showAllView: boolean = false;

    /**
     * 是否能看见所有设施
     */
    public set showAllView(v: boolean) {
        this._showAllView = v;
    }

    public get showAllView(): boolean {
        return this._showAllView;
    }

    /**
     * 获取视野覆盖率, 0-1;
     */
    public get coveringRate(): number {
        if (this.showAllView)
            return 1;
        let viewCount = this.viewArr.reduce((acc, current) => acc + current, 0);
        return viewCount / this.viewArr.length;
    }

    protected start(): void {
        this.viewArr = new Uint8Array(MapLength * MapLength);
        super.start();
        this.getComponentInChildren(cc.Label).string = Global.currentGameData.enemy.find(item => item.roleId == this.roleId).nikeName;
        this.addComponent(AiFindHome);
        this.aiGameAction = this.addComponent(AiGmaeAction);
        this.facilityHurtMyFacility = new Map<DestructibleFacility, number>();
        this.facilityHurtMyFlyer = new Map<DestructibleFacility, number>();
        this.facilityMyHurt = new Map<DestructibleFacility, number>();
    }

    /**
     * 安家时，把主基地加入facilityHurtMyFacility
     * 监听所有的被攻击事件
     * 加入策略AI
     */
    public makeHome(): boolean {
        let ret = super.makeHome();
        if (!ret) return false;

        let mainHome = this.facilityArr[FacilityType.主基地][0] as DestructibleFacility;
        this.facilityMyHurt.set(mainHome, 0);

        this.node.on(Player.EventType.我的设施被攻击, this.onHurtMyFacility, this);
        this.node.on(Player.EventType.我的飞行物被攻击, this.onHurtMyFlyer, this);

        this.aiGameAction.init(this);
        this.aiGameAction.run();
        return ret;
    }

    /**
     * 我的飞行物被攻击
     * @param myflyer 我的飞行物
     * @param killer 
     * @returns 
     */
    onHurtMyFlyer(myflyer: Flyer, killer: Killer) {
        if (!killer.player) return;
        if (killer.facility) {
            if (this.facilityHurtMyFlyer.has(killer.facility)) {
                let allDamage = this.facilityHurtMyFlyer.get(killer.facility);
                allDamage += killer.domage;
                this.facilityHurtMyFlyer.set(killer.facility, allDamage);
            } else {
                this.facilityHurtMyFlyer.set(killer.facility, killer.domage);
                killer.facility.node.on(DestructibleFacility.EventType.摧毁, () => {
                    this.facilityHurtMyFlyer.delete(killer.facility);
                }, this);
            }
        } else {
            //如果设施被摧毁了，这锅甩给总伤害值最大的敌方设施
            if (this.facilityHurtMyFlyer.size > 0) {
                let [maxKey, maxValue] = Array.from(this.facilityHurtMyFlyer.entries()).reduce((maxEntry, [key, value]) => {
                    return value > maxEntry[1] ? [key, value] : maxEntry;
                }, [null, -0]);
                maxValue += killer.domage;
                this.facilityHurtMyFlyer.set(maxKey, maxValue);
            } else {
                //如果没有攻打过我 随机一个得了
                if (killer.player.allFacility && killer.player.allFacility.length) {
                    let randomFacility = Utils.getRandomChoose(killer.player.allFacility);
                    this.facilityHurtMyFlyer.set(randomFacility, killer.domage);
                    randomFacility.node.on(DestructibleFacility.EventType.摧毁, () => {
                        this.facilityHurtMyFlyer.delete(randomFacility);
                    }, this);
                }
            }
        }
    }


    /**
     * 自己的设施被攻击时
     * 以自己的设施为Key , 记录攻击我的设施
     * @param selfFacility 
     * @param killer 
     * @returns 
     */
    onHurtMyFacility(selfFacility: DestructibleFacility, killer: Killer) {
        if (!killer.player) return;
        if (killer.facility) {
            let enemyFacility = killer.facility;
            if (this.facilityHurtMyFacility.has(enemyFacility)) {
                let allDamage = this.facilityHurtMyFacility.get(enemyFacility);
                allDamage += killer.domage;
                this.facilityHurtMyFacility.set(enemyFacility, allDamage);
            } else {
                this.facilityHurtMyFacility.set(enemyFacility, killer.domage);
                enemyFacility.node.on(DestructibleFacility.EventType.摧毁, () => {
                    this.facilityHurtMyFacility.delete(enemyFacility);
                    enemyFacility.node.targetOff(this);
                }, this);
            }
        }
    }

    /**
     * 主基地被破环
     * 清除
     */
    public die(killer: Killer) {
        super.die(killer);
        this.node.targetOff(this);
        this.facilityHurtMyFacility.clear();
        this.facilityHurtMyFlyer.clear();
        this.facilityMyHurt.clear();
        this.getComponent(AiGmaeAction).unscheduleAllCallbacks();
    }

    /**
     * 建造设施，把设施加入facilityMyHurt
     * @param facilityType 
     * @param locaitons 
     * @param price 
     * @returns 
     */
    addFacility(facilityType: FacilityType, locaitons: Location[], price?: { diamond: number; oil: number; }): DestructibleFacility {
        let facility = super.addFacility(facilityType, locaitons, price);
        this.facilityMyHurt.set(facility, 0);
        facility.node.on(DestructibleFacility.EventType.摧毁, () => {
            this.facilityHurtMyFacility.delete(facility);
            facility.node.targetOff(this);
        }, this);
        return facility;
    }

    /**
     * 获得视野
     * @param location 
     */
    public getLocationView(location: Location): void {
        //判断是否已经看得见
        if (!this.isLocationVisible(location)) {
            this.viewArr[location.locationY * MapLength + location.locationX] = 1;
            let fac = GameManager.instance.getFacilityByLocation(location);
            if (fac instanceof MainHome && fac.player != this && this.discoveredEnemy.findIndex(de => de == (<MainHome>fac).player) == -1) {
                //发现新敌人
                this.discoveredEnemy.push(fac.player)
                fac.player.node.emit(Player.EventType.被发现, this);
            }
        }
    }

    public onGetNewDomain(newDomain: Location[]): void {
        super.onGetNewDomain(newDomain);
        newDomain.forEach(item => this.getLocationView(item));
    }

    /**
     * 检查这个位置是否看得见
     * @param location 
     * @returns 
     */
    public isLocationVisible(location: Location): boolean {
        return !!this.viewArr[location.locationY * MapLength + location.locationX]
    }

    /**
     * 这个设施是否看得见
     * @param facility 
     * @returns 
     */
    public isFacilityVisible(facility: Facility): boolean {
        return !!facility.locations.find(locaiton => this.isLocationVisible(locaiton));
    }

    /**
     * 将这个位置标识为视野内
     * @param location 
     */
    public setLocationVisible(location: Location) {
        this.viewArr[location.locationY * MapLength + location.locationX] = 1;
    }

    public loseDomain(domain: Location[]) {
        return;
        //领地采取使用时动态获取的方式
    }

    /**
     * 获取区域内所有视线内的设施
     */
    public getFacilitiesByAraeAndView(leftUp: Location, rightDown: Location, condition?: (facility: Facility) => boolean): Facility[] {
        leftUp.locationX = Math.max(0, leftUp.locationX);
        leftUp.locationY = Math.max(0, leftUp.locationY);
        rightDown.locationX = Math.min(MapLength - 1, rightDown.locationX);
        rightDown.locationY = Math.min(MapLength - 1, rightDown.locationY);
        let result: Facility[] = [];
        for (let y = leftUp.locationY; y <= rightDown.locationY; y++) {
            for (let x = leftUp.locationX; x < rightDown.locationX; x++) {
                let tempLocation = { locationX: x, locationY: y };
                if (this.isLocationVisible(tempLocation)) {
                    let facility = GameManager.instance.getFacilityByLocation(tempLocation)
                    if (facility) {
                        if (condition && condition(facility)) {
                            result.push(facility);
                        }
                    }
                }
            }
        }
        return result;
    }

    /**
     * 获取领地内所有油矿 (未安装采油机)
     */
    public getOilMineByDomain(): Mine[] {
        let result = [];
        for (let i = 0; i < this.domainArr.length; i++) {
            let fac = GameManager.instance.getFacilityByLocation(this.domainArr[i]);
            if (fac && fac.facilityType == FacilityType.油矿) {
                result.push(fac);
            }
        }
        return result;
    }

    protected onFindNewEnemy(player: Player): void {

    }

    /**
     * 获取区域内所有地块
     * @param leftUp 
     * @param rightDown 
     * @param rhombu  是否为菱形
     */
    private getAllLocationByArea(leftUp: Location, rightDown: Location, rhombu: boolean): Location[] {
        let left = Math.max(0, leftUp.locationX);
        let top = Math.max(0, leftUp.locationY);
        let right = Math.min(MapLength - 1, rightDown.locationX);
        let bottom = Math.min(MapLength - 1, rightDown.locationY);
        let temps = [];
        if (rhombu) {
            let centerLocation: Location = { locationX: left + Math.round((right - left) / 2), locationY: top + Math.round((bottom - top) / 2) }
            let size = right - left;
            for (let y = centerLocation.locationY, sum = 0; y >= top; y--, sum++) {
                let row = size - sum * 2;
                for (let j = 0; j <= row; j++) {
                    temps.push({ locationX: left + sum + j, locationY: y });
                }
            }
            for (let y = centerLocation.locationY + 1, sum = 1; y <= bottom; y++, sum++) {
                let row = size - sum * 2;
                for (let j = 0; j <= row; j++) {
                    temps.push({ locationX: left + sum + j, locationY: y });
                }
            }
        } else {
            for (let x = left; x <= right; x++) {
                for (let y = top; y <= bottom; y++) {
                    temps.push({ locationX: x, locationY: y });
                }
            }
        }

        return temps;
    }
}
